[t:/]$ 지식_

go 파일 저장소를 사용하는 스택 구현

2020/06/23

쪼렙 스터디차 깔짝깔짝 만들어봄. 아직 만들다 만 것임.

굳이 기본 자료형과 파일 함수를 쓰지않고 돌아돌아 unsafe스럽게 만든 것은 속도 등등을 위한 것.

아직 MT-Safe 하지 않음.

package main

import (
    "unsafe"
    "os"
    "fmt"
    "syscall"
    "reflect"
//  "flag"
    "golang.org/x/sys/unix"
)

const DATA_SIZE int = 16

type data struct {
//  klen int
    v [DATA_SIZE]byte
}

const INT_SIZE  int = int(unsafe.Sizeof(int(0)))
const MAX_ITEM  int = 4
const ITEM_SIZE int = int(unsafe.Sizeof(data{}))
const FILE_SIZE int = ITEM_SIZE * MAX_ITEM

type data_file struct {
    pos1 int
    dummy1 [4096 - INT_SIZE]byte
    items [MAX_ITEM]data
    dummy3 [4096 - (MAX_ITEM * ITEM_SIZE) % 4096]byte
    pos2 int
    dummy2 [4096 - INT_SIZE]byte    
}

func Open_data(init bool, filename string) []data_file {

    size := int(unsafe.Sizeof( data_file{} ))
    println(size)

    var map_file *os.File
    var err error

    if init {

        map_file, err = os.Create(filename)

    } else {
        map_file, err = os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_SYNC, 0755)
    }

    defer map_file.Close()

    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    _, err = map_file.Seek(int64(size - 1), 0)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    _, err = map_file.Write([]byte{0})
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    mmap, err := syscall.Mmap(int(map_file.Fd()), 0, int(size), syscall.PROT_READ | syscall.PROT_WRITE, syscall.MAP_SHARED)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    if init {
        for i := range mmap {
            mmap[i] = 0
        }
    }

    header := (*reflect.SliceHeader)(unsafe.Pointer(&mmap))
    header.Len = 1
    header.Cap = 1

    map_data := *(*[]data_file)(unsafe.Pointer(header))

    err = map_file.Close()    

    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }    

    return map_data
}

func Close_data(mmap []data_file) {

    header := (*reflect.SliceHeader)(unsafe.Pointer(&mmap))
    header.Len = int(unsafe.Sizeof(data_file{}))
    header.Cap = header.Len 

    unmap := *(*[]byte)(unsafe.Pointer(&mmap))
    err := syscall.Munmap(unmap)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
}

var sp int = 0
var gpos1 *int
var gpos2 *int
var max_pos *int

func push(item_data []byte, store []data_file ) {

    if sp == MAX_ITEM {
        fmt.Fprintf(os.Stderr, "용량 초과, 마지막 푸시 = %s\n", string(item_data))
        return
    }

    copy(store[0].items[*gpos1].v[:], item_data)
    *gpos1++
    *gpos2++
    sp++

}

func pop(store []data_file ) (ret []byte) {

    sp--

    if sp < 0 {
//      ret = []byte("")
        ret = nil
        fmt.Fprintf(os.Stderr, "스택이 비었음\n")
        return 
    }

    *gpos1--
    *gpos2--    

    ret = store[0].items[*gpos1].v[:]

    return
}

func main() {

    println(FILE_SIZE)

//  file := flag.String("file", "stack.dat", "스택 저장소 파일 이름")
//  max_items := flag.Int("max-item", MAX_ITEM, "최대 아이템 갯수")
//  bucket_size := flag.Int("bucket-size", DATA_SIZE, "버킷 크기")

    my_data := Open_data(true, "my_data.dat")

    header := (*reflect.SliceHeader)(unsafe.Pointer(&my_data[0].pos1))
    header.Len = 4096
    header.Cap = 4096

    unix.Msync(*(*[]byte)(unsafe.Pointer(header)), unix.MS_SYNC)

    header = (*reflect.SliceHeader)(unsafe.Pointer(&my_data[0].pos2))
    header.Len = 4096
    header.Cap = 4096

    unix.Msync(*(*[]byte)(unsafe.Pointer(header)), unix.MS_SYNC)    

    gpos1 = &my_data[0].pos1
    gpos2 = &my_data[0].pos2

    push([]byte("가나"), my_data)
    push([]byte("다라"), my_data)
    push([]byte("마바"), my_data)
    push([]byte("하하"), my_data)
    push([]byte("호호"), my_data)
    println(string(pop(my_data)))
    println(string(pop(my_data)))
    println(string(pop(my_data)))
    println(string(pop(my_data)))
    println(string(pop(my_data)))
    println(string(pop(my_data)))

    defer Close_data(my_data)

}




공유하기













[t:/] is not "technology - root". dawnsea, rss